# coding: UTF-8
"""
将项目描述文件解析为任务队列并执行
"""
import json
import glob
import os
import sys
import argparse
import time
from multiprocessing import Pool


VERSION = "1.1.0"


class ProjectParser(object):
    '''
    项目文件解析
    '''

    NAME = ""
    AS = ""
    CC = ""
    LD = ""
    OBJCOPY = ""
    AR = ""
    Type = ""
    OutPath = ""
    IsCreateBin = False
    IsCreateHex = False
    ASFlag = []
    CCFlag = []
    LDFlag = []
    Includes = []
    SrcFiles = []

    def __init__(self, data):
        # 工具链配置
        if data.get("toolchain", ""):
            path = data["toolchain"].get("path", "")
            prefix = data["toolchain"].get("prefix", "")
            self.AS = "%s%s%s" % (
                path, prefix, data["toolchain"]["as"]) if data["toolchain"].get("as", "") else ""
            self.CC = "%s%s%s" % (
                path, prefix, data["toolchain"]["cc"]) if data["toolchain"].get("cc", "") else ""
            self.LD = "%s%s%s" % (
                path, prefix, data["toolchain"]["ld"]) if data["toolchain"].get("ld", "") else ""
            self.OBJCOPY = "%s%s%s" % (
                path, prefix, data["toolchain"]["objcopy"]) if data["toolchain"].get("objcopy", "") else ""
            self.AR = "%s%s%s" % (
                path, prefix, data["toolchain"]["ar"]) if data["toolchain"].get("as", "") else ""
            # 编译参数
            self.ASFlag = " ".join(data["toolchain"].get("asflag", []))
            self.CCFlag = " ".join(data["toolchain"].get("ccflag", []))
            self.LDFlag = " ".join(data["toolchain"].get("ldflag", []))
        # 项目配置
        if data.get("project", ""):
            self.NAME = data['project'].get('name', "project")
            # 输出设置
            if data['project'].get("output", ""):
                # self.Type = data['output'].get("type", "elf")
                self.OutPath = data['project']['output'].get("path", "")
                self.IsCreateBin = data['project']['output'].get("bin", False)
                self.IsCreateHex = data['project']['output'].get("hex", False)
            # 头文件路径
            if data['project'].get("include", []):
                self.Includes = " ".join(
                    map(lambda x: "-I " + x, data['project']['include']))
            # 源文件
            if data['project'].get("src", []):
                for item in data['project']['src']:
                    self.SrcFiles.extend(glob.glob(item))

    def GetTargetFile(self, Ext):
        return self.OutPath + self.NAME + Ext

    def GetOutFile(self, infile):
        return self.OutPath + os.path.basename(infile).split(".")[0] + ".o"
        
    def GetLinkCMD(self):
        return "@%s %s -o %s %s" % (self.LD, " ".join(
            glob.glob(self.OutPath + "*.o")), self.GetTargetFile(".elf"), self.LDFlag)

    def GetCreateBinCMD(self):
        return "@%s %s %s -Obinary" % (self.OBJCOPY, self.GetTargetFile(".elf"), self.GetTargetFile(".bin"))

    def GetCreateHexCMD(self):
        return "@%s %s %s -Oihex" % (self.OBJCOPY, self.GetTargetFile(".elf"), self.GetTargetFile(".hex"))

    def GetCompileTasks(self):
        _taskList = []
        for infile in self.SrcFiles:
            outfile = self.GetOutFile(infile)
            if os.path.exists(outfile):  # 跳过没有变化文件
                if os.path.getmtime(outfile) > os.path.getmtime(infile):
                    continue
            if os.path.splitext(infile)[1] in [".c",".cpp"]:
                _taskList.append("@%s -c %s -o %s %s %s" %
                                 (self.CC, infile, outfile, self.Includes, self.CCFlag))
            if os.path.splitext(infile)[1] == ".s" or os.path.splitext(infile)[1] == ".S":
                _taskList.append("@%s -c %s -o %s %s %s" %
                                 (self.AS, infile, outfile, self.Includes, self.ASFlag))
        return _taskList

def main():
    print("main")

def compile_func(project):
    if not os.path.exists(project.OutPath):  # 检查输出目录
        os.makedirs(project.OutPath)
    start = time.clock()
    print("正在编译。。。")
    pool = Pool()
    pool.map(excute_shell, project.GetCompileTasks())
    pool.close()
    pool.join()
    # 多线程并发
    # exit()
    # 链接
    if project.Type == "lib":  # 生成库
        pass
        # os.system(project.GetArCMD())
    else:  # 连接
        os.system(project.GetLinkCMD())
    
    # 完成
    end = time.clock()
    print("编译完成，耗时%s" % (end - start))

def clean_func(project):
    '''清除命令处理函数'''
    for delfile in glob.glob(project.OutPath + "*.*"):
        os.remove(delfile)

def flash_func(project):
    '''下载命令处理函数'''
    os.system("%s/mqjlink -o 0x08000000 -d STM32F405RG -f %s" %
              (sys.path[0], project.GetTargetFile(".bin")))

def check_project_file(args):
    '''
    检查项目描述文件是否正确
    '''
    if not args.file:
        args.file = 'project.json'
    if not os.path.isfile(args.file):
        print("未找到项目描述文件%s" % (args.file))
        exit()
    else:
        data = json.load(open(args.file, encoding='utf8'))
        if not data.get('version', "") == VERSION:
            print("项目描述文件版本不兼容")
            exit()
        else:
            return data

def excute_shell(cmd):
    """执行shell命令"""
    os.system(cmd)


if __name__ == "__main__":
    # 解析命令行参数
    parser = argparse.ArgumentParser(prog='mqmake', description='mqmake tool')
    parser.add_argument('-f', "--file", help='project config file')
    parser.set_defaults(func=main)
    subparsers = parser.add_subparsers(
        title='subcommands', help='mqmake sub commands')
    # 编译子命令
    cc_parser = subparsers.add_parser('cc', help='compile project')
    cc_parser.set_defaults(func=compile_func)
    # 安装子命令
    clean_parser = subparsers.add_parser(
        'clean', help='clean project temp file')
    clean_parser.set_defaults(func=clean_func)
    flash_parser = subparsers.add_parser(
        'flash', help='download bin file')
    flash_parser.set_defaults(func=flash_func)
    args = parser.parse_args()
    args.func(ProjectParser(check_project_file(args)))
